home *** CD-ROM | disk | FTP | other *** search
- /* Tidelib Common functions used by XTide and Tide.
- Last modified 1/4/96
-
- This program uses the harmonic method to compute tide levels.
- All of the data and constants are read in from the harmonics file.
- Please refer to ReadMe Mac and README for more information.
-
-
- Copiright (C) 1996 Mikhail Fridberg
- Copyright (C) 1995 David Flater.
- Also starring: Jef Poskanzer; Rob Miracle; Geoff Kuenning;
- Dale DePriest.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
- The tide prediction algorithm used in this program was developed
- with United States Government funding, so no proprietary rights
- can be attached to it. For more information, refer to the
- following publications:
-
- Manual of Harmonic Analysis and Prediction of Tides. Special
- Publication No. 98, Revised (1940) Edition. United States
- Government Printing Office, 1941.
-
- Computer Applications to Tides in the National Ocean Survey.
- Supplement to Manual of Harmonic Analysis and Prediction of Tides
- (Special Publication No. 98). National Ocean Service, National
- Oceanic and Atmospheric Administration, U.S. Department of
- Commerce, January 1982.
-
- */
-
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <signal.h>
- #include "unistd.h"
- #include <unix.h>
- #include <time.h>
- #include <assert.h>
- #include <string.h>
- #include "sys/time.h"
- #include <ctype.h>
- #include <Script.h>
-
- #include "tidelib.h"
- #include "arglib.h"
- #include "glyphs.h"
- #include <GestaltEqu.h>
- #include <Traps.h>
- #include <OSUtils.h>
- /* Compatibility by Dale DePriest */
-
- #ifdef OS2
- #include <float.h>
- #endif /* OS2 */
-
- /* Typo prevention */
- #define DAYSECONDS 86400
- #define HOURSECONDS 3600
-
- /* Exported variables */
- int gHasFPU;
- int gTimezone=0;
- char hfile_name[MAXARGLEN+1], location[MAXARGLEN+1], *ppm = NULL,
- tzfile[MAXARGLEN+1];
- char next_ht_text[13], next_ht_date[11], next_lt_text[13],
- next_lt_date[11], *geometry = NULL;
- char *fgrise_color_arg = NULL, *fgfall_color_arg = NULL,
- *bg_color_arg = NULL, *fgtext_color_arg = NULL, *fgmark_color_arg = NULL,
- *fgmllw_color_arg = NULL, *fgmiddle_color_arg = NULL;
- int tadjust = 0, utc = 0, list = 0, checkyear = 0, text = 0, skinny = 0,
- now = 0, graphmode = 0, httimeoff = 0, lttimeoff = 0, tstep = 180,
- middle = 0, mark = 0, mllw = 0, lines = 1, PPMWIDTH = 960,
- PPMHEIGHT = 300, hinc = 0, tinc = 0, loctz = 0, iscurrent = 0,
- curonly = 0, toplines = 0, hincmagic = 0, calendar = 0, banner = 0;
- time_t next_ht = 0, prev_ht = 0, faketime = 0, epoch = 0;
- double amplitude, htleveloff = 0.0, ltleveloff = 0.0, DATUM, marklev;
- Cursor waitCursor;
- CursHandle hCurs;
- /* Local variables */
-
- static int year = 0, meridian = 0;
-
- /* Tide-prediction storage -- cst == constituent */
-
- static int num_csts = 0, num_nodes = 0, num_epochs = 0, first_year = 0;
- static double *cst_speeds, **cst_epochs, **cst_nodes, *loc_amp, *loc_epoch,
- *work;
-
- /* Exit without core dump on assertion failures. */
- void
- sigabort ()
- {
- exit (-1);
- }
-
- /* User-friendly error messages */
- void
- barf (enum tideerr err)
- {
- fprintf (stderr, "Tidelib Fatal Error: ");
- switch (err) {
- case BADCOLORSPEC:
- fprintf (stderr, "BADCOLORSPEC\n");
- fprintf (stderr,
- "One of your specified colors is not understood. This may be because it is\n\
- not in rgb.txt, or because you used the wrong syntax. In PPM mode, colors\n\
- must be specified as rgb:hh/hh/hh, where hh is a 2-digit hexadecimal number.\n\
- Other formats are possible under X; type 'man X' for an explanation of them.\n");
- break;
- case BADGEOMETRY:
- fprintf (stderr, "BADGEOMETRY\n");
- fprintf (stderr,
- "In PPM mode, geometry must be specified as WxH, where W and H are width and\n\
- height in pixels respectively. Other formats are possible under X; type\n\
- 'man X' for an explanation of them. This error is also generated if the\n\
- geometry that you specify is too small or too large in one or both directions.\n");
- break;
- case CANTOPENDISPLAY:
- fprintf (stderr, "CANTOPENDISPLAY\n");
- fprintf (stderr,
- "Can't open the X display. Check the setting of the DISPLAY environment\n\
- variable or the value supplied with the -display switch. You may also need\n\
- to fix your X authorities with xhost or xauth.\n");
- break;
- case WANTMOREARGS:
- fprintf (stderr, "WANTMOREARGS\n");
- fprintf (stderr,
- "Your last switch wants an argument that you did not provide.\n");
- break;
- case CONFIGFAIL:
- fprintf (stderr, "CONFIGFAIL\n");
- perror ("fopen");
- fprintf (stderr,
- "Could not open the config file that you specified.\n");
- break;
- case CANTOPENFILE:
- fprintf (stderr, "CANTOPENFILE\n");
- perror ("fopen");
- fprintf (stderr,
- "Could not open a file.\n");
- break;
- case BADINTEGER:
- fprintf (stderr, "BADINTEGER\n");
- fprintf (stderr,
- "One of your switches wants an integer but didn't get one.\n");
- break;
- case BADFLOAT:
- fprintf (stderr, "BADFLOAT\n");
- fprintf (stderr,
- "One of your switches wants a floating point number but didn't get one.\n");
- break;
- case BADHHMM:
- fprintf (stderr, "BADHHMM\n");
- fprintf (stderr,
- "Offset must be of the form [-]HH:MM where HH is hours and MM is minutes.\n"
- );
- break;
- case STRETCHTOOSMALL:
- fprintf (stderr, "STRETCHTOOSMALL\n");
- fprintf (stderr, "-gstretch needs a positive value.\n");
- break;
- case STRETCHTOOBIG:
- fprintf (stderr, "STRETCHTOOBIG\n");
- fprintf (stderr, "-gstretch wants a smaller number.\n");
- break;
- case BADTIMESTAMP:
- fprintf (stderr, "BADTIMESTAMP\n");
- fprintf (stderr,
- "-gstart wants a timestamp of the form YYYY:MM:DD:HH:MM. Example -- half past\n\
- midnight, June 1, 1995: 1995:06:01:00:30. This error may also be raised if\n\
- you specify a non-existent time, such as February 31st or the hour that is\n\
- skipped because of Daylight Savings Time, or go outside the acceptable range\n\
- of dates (i.e. before 1970 or after 2037 on most Unix machines).\n");
- break;
- case MISSINGYEAR:
- fprintf (stderr, "MISSINGYEAR\n");
- fprintf (stderr,
- "In order to calculate tides for a given year, the node factors and\n\
- equilibrium arguments for that year must be in the harmonics file. The\n\
- harmonics file that you are using only supports the following years:\n");
- if (num_nodes < num_epochs)
- num_epochs = num_nodes;
- fprintf (stderr, " %d through %d\n", first_year,
- first_year+num_epochs-1);
- break;
- case OFFSETSTEXTONLY:
- fprintf (stderr, "OFFSETSTEXTONLY\n");
- fprintf (stderr,
- "-hloff, -htoff, -lloff, and -ltoff are only supported in text mode and cannot\n\
- be used with -graph, -ppm, -mark, or -banner.\n");
- break;
- default:
- assert (0);
- }
- exit (-1);
- }
-
- /* Allocate tide-prediction storage except for node factors and epochs. */
- static void
- allocate_cst ()
- {
- assert (num_csts);
- assert (cst_speeds = (double *) malloc (num_csts * sizeof (double)));
- assert (loc_amp = (double *) malloc (num_csts * sizeof (double)));
- assert (loc_epoch = (double *) malloc (num_csts * sizeof (double)));
- assert (work = (double *) malloc (num_csts * sizeof (double)));
- }
-
- /* Allocate cst_nodes. */
- static void
- allocate_nodes ()
- {
- int a;
- assert (num_csts);
- assert (num_nodes);
- assert (cst_nodes = (double **) malloc (num_csts * sizeof (double *)));
- for (a=0;a<num_csts;a++)
- assert (cst_nodes[a] = (double *) malloc (num_nodes * sizeof (double)));
- }
-
- /* Allocate cst_epochs. */
- static void
- allocate_epochs ()
- {
- int a;
- int temp_epochs,temp_csts;
-
- assert (num_csts);
- assert (num_epochs);
- temp_epochs = num_epochs * sizeof (double);
- temp_csts = num_csts * sizeof (double);
- assert (cst_epochs = (double **) malloc (temp_csts));
- for (a=0;a<num_csts;a++){
- cst_epochs[a] = (double *) malloc (temp_epochs);
- assert (cst_epochs[a]);
- }
- }
-
- /* Turn a time displacement of the form [-]HH:MM into the number of seconds. */
- int
- hhmm2seconds (char *hhmm)
- {
- long h, m;
- char s;
- if (sscanf (hhmm, "%d:%d", &h, &m) != 2)
- barf (BADHHMM);
- if (sscanf (hhmm, "%c", &s) != 1)
- barf (BADHHMM);
- if (h < 0 || s == '-')
- m = -m;
- return h*(long)HOURSECONDS + m*60;
- }
-
- /* Get rid of trailing garbage in linrec */
- static char *
- nojunk (char *linrec)
- {
- char *a;
- a = &(linrec[strlen(linrec)]);
- while (a > linrec)
- if (*(a-1) == '\n' || *(a-1) == '\r' || *(a-1) == ' ')
- *(--a) = '\0';
- else
- break;
- return linrec;
- }
-
- /* Slackful strcmp; 0 = match. It's case-insensitive and accepts a
- prefix instead of the entire string. The second argument is the
- one that can be inter. */
- static int
- slackcmp (char *a, char *b)
- {
- int c, cmp, n;
- n = strlen (b);
- if ((int)(strlen (a)) < n)
- return 1;
- for (c=0;c<n;c++)
- {
- cmp = ((a[c] >= 'A' && a[c] <= 'Z') ? a[c] - 'A' + 'a' : a[c])
- -
- ((b[c] >= 'A' && b[c] <= 'Z') ? b[c] - 'A' + 'a' : b[c]);
- if (cmp)
- return cmp;
- }
- return 0;
- }
-
- /* Read a line from the harmonics file, skipping comment lines */
- static int
- next_line (FILE *fp, char linrec[linelen], int end_ok)
- {
- do {
- if (!fgets (linrec, linelen, fp)) {
- if (end_ok)
- return 0;
- else {
- fprintf (stderr, "Unexpected end of harmonics file '%s'\n",
- hfile_name);
- exit (-1);
- }
- }
- } while (linrec[0] == '#');
- return 1;
- }
-
- /* Convert a struct tm in GMT back to a time_t. */
- time_t
- tm2gmt (struct tm *ht)
- {
- time_t temp;
-
- #if defined(sun) && !defined(SVR4) && !defined(__svr4__)
- /* Old SunOS */
- temp = timegm (ht);
- /* {
- struct tm *sunos;
- temp = timelocal (ht);
- sunos = localtime (&temp);
- temp += sunos->tm_gmtoff;
- } */
- #else
- assert ((temp = mktime (ht)) != -1);
- /* Determine the local time zone offset and correct for it */
- /* Taking timezone from gettimeofday didn't work (always zero) */
- #ifdef ultrix
- {
- /* Ultrix compatibility courtesy of Rob Miracle */
- struct tm *tzinfo;
- tzinfo = localtime (&temp);
- temp += tzinfo->tm_gmtoff;
- }
- #else
- localtime(&temp);
- temp += gTimezone;
-
- #endif
- #endif
- return temp;
- }
-
- /* Calculate time_t of the epoch. */
- static void
- set_epoch ()
- {
- struct tm ht;
- if (year < first_year || year >= first_year + num_epochs) {
- fprintf (stderr, "Tidelib: Don't have equilibrium arguments for %d\n",
- year);
- barf (MISSINGYEAR);
- }
- ht.tm_year = year - 1900;
- ht.tm_sec = ht.tm_min = ht.tm_hour = ht.tm_mon = 0;
- ht.tm_mday = 1;
- ht.tm_isdst = 0;
- epoch = tm2gmt (&ht);
- }
-
- /* Attempt to load up the local time zone of the location. Moof! */
- void
- change_time_zone (char *tz)
- {
- static char env_string[MAXARGLEN+1];
- #ifdef BROKEN_ZONEINFO
-
- /* This is not a comprehensive time zone translation since many time
- zones are not represented in the harmonics file. Additional
- translations will be added as needed in future versions of
- XTide. */
-
- /* I have not tried to encode the different systems for DST. If you
- have an encoding that is known to be correct, please send it. It
- should look something like EST5EDT4,116/2:00:00,298/2:00:00. */
-
- /* United States. YST is Yukon Standard Time, sometimes written as
- AKST (Alaska Standard Time). Hawaii doesn't do DST. */
-
- if (!strcmp (tz, ":US/Eastern"))
- strcpy (tz, "EST5EDT");
- else if (!strcmp (tz, ":US/Central"))
- strcpy (tz, "CST6CDT");
- else if (!strcmp (tz, ":US/Mountain"))
- strcpy (tz, "MST7MDT");
- else if (!strncmp (tz, ":US/Pacific", 11))
- strcpy (tz, "PST8PDT");
- else if (!strcmp (tz, ":US/Alaska"))
- strcpy (tz, "YST9YDT");
- else if (!strcmp (tz, ":US/Hawaii"))
- strcpy (tz, "HST10");
-
- /* Canada */
-
- else if (!strcmp (tz, ":Canada/Pacific"))
- strcpy (tz, "PST8PDT");
- else if (!strcmp (tz, ":Canada/Eastern"))
- strcpy (tz, "EST5EDT");
- else if (!strcmp (tz, ":Canada/Atlantic"))
- strcpy (tz, "AST4ADT");
- else if (!strcmp (tz, ":Canada/Newfoundland"))
- strcpy (tz, "NST3:30NDT");
-
- /* Mexico */
-
- else if (!strcmp (tz, ":Mexico/BajaNorte"))
- strcpy (tz, "PST8PDT");
- else if (!strcmp (tz, ":Mexico/BajaSur"))
- strcpy (tz, "MST7");
- else if (!strcmp (tz, ":Mexico/General"))
- strcpy (tz, "CST6");
-
- /* South America */
- /* These will be really screwed up since DST is in December */
-
- else if (!strcmp (tz, ":Chile/EasterIsland"))
- strcpy (tz, "LST6");
- else if (!strcmp (tz, ":Brazil/East"))
- strcpy (tz, "LST3");
-
- /* Asia */
-
- else if (!strcmp (tz, ":PRC"))
- strcpy (tz, "CST-8");
- else if (!strcmp (tz, ":Hongkong"))
- strcpy (tz, "HKT-8");
- else if (!strcmp (tz, ":Singapore"))
- strcpy (tz, "SST-8");
- else if (!strcmp (tz, ":Japan"))
- strcpy (tz, "JST-9");
-
- /* The Rest Of Us */
- /* DST will be screwed up for these */
- /* The weird syntax for WET is from Dale's file; I did MET the same way. */
-
- else if (!strcmp (tz, ":WET"))
- strcpy (tz, "WET0WETDST");
- else if (!strcmp (tz, ":MET"))
- strcpy (tz, "MET-1METDST");
- else if (!strcmp (tz, ":Iceland"))
- strcpy (tz, "WET0");
- else if (!strcmp (tz, ":Australia/Queensland"))
- strcpy (tz, "EST-10");
- else if (!strcmp (tz, ":GB-Eire"))
- strcpy (tz, "GMT0BST");
-
- /* GMT and offsets therefrom, which will be called LST for Local
- Standard Time. */
-
- else if (!strcmp (tz, ":GMT"))
- strcpy (tz, "GMT0");
- else if (!strcmp (tz, ":UTC"))
- strcpy (tz, "GMT0");
- else if (!strncmp (tz, ":GMT", 4)) {
- int a;
- assert (sscanf (tz+4, "%d", &a) == 1);
- sprintf (tz, "LST%d", -a);
- }
-
- #endif
- /* assert (setenv ("TZ", tz, 1) == 0); */
- /* According to the SYSV man page, I can't alter env_string ever again. */
- sprintf (env_string, "TZ=%s", tz);
- // This is part that makes it possible to use time in local time zone.
- // It doesn't work on Mac, so it's commented out
- // assert (putenv (env_string) == 0);
- // tzset ();
-
- }
-
- /* Load harmonics data */
- void
- load_data ()
- {
- FILE *fp;
- char linrec[linelen], junk[80];
- int a, b;
- if (!(fp = fopen (hfile_name, "r"))) {
- fprintf (stderr, "Could not open harmonics file '%s'\n", hfile_name);
- barf (CANTOPENFILE);
- }
- next_line (fp, linrec, 0);
- assert (sscanf (linrec, "%d", &num_csts) == 1);
- allocate_cst ();
- /* Load constituent speeds */
- for (a=0;a<num_csts;a++) {
- next_line (fp, linrec, 0);
- assert (sscanf (linrec, "%s %lf", junk, &(cst_speeds[a])) == 2);
- cst_speeds[a] /= 3600.0; /* Convert to degrees per second */
- }
- /* Get first year for nodes and epochs */
- next_line (fp, linrec, 0);
- assert (sscanf (linrec, "%d", &first_year) == 1);
-
- /* Load epoch table */
- next_line (fp, linrec, 0);
- assert (sscanf (linrec, "%d", &num_epochs) == 1);
- allocate_epochs ();
- for (a=0;a<num_csts;a++) {
- assert (fscanf (fp, "%s", linrec) == 1);
- for (b=0;b<num_epochs;b++)
- assert (fscanf (fp, "%lf", &(cst_epochs[a][b])) == 1);
- }
- /* Sanity check */
- assert (fscanf (fp, "%s", linrec) == 1);
- assert (!strcmp (linrec, "*END*"));
-
- /* Load node factor table */
- next_line (fp, linrec, 0); /* Skip lingering CR from *END* */
- next_line (fp, linrec, 0);
- assert (sscanf (linrec, "%d", &num_nodes) == 1);
- allocate_nodes ();
- for (a=0;a<num_csts;a++) {
- assert (fscanf (fp, "%s", linrec) == 1);
- for (b=0;b<num_nodes;b++)
- assert (fscanf (fp, "%lf", &(cst_nodes[a][b])) == 1);
- }
- /* Sanity check */
- assert (fscanf (fp, "%s", linrec) == 1);
- assert (!strcmp (linrec, "*END*"));
-
- /* List locations and exit? */
- if (list) {
- next_line (fp, linrec, 0); /* Skip lingering CR from *END* */
- while (next_line (fp, linrec, 1)) {
- nojunk (linrec);
- if (curonly)
- if (!strstr (linrec, "Current"))
- continue;
- printf ("%s", linrec);
- next_line (fp, linrec, 0);
- if (list == 2)
- printf ("\t%s\n", nojunk(linrec));
- else
- printf ("\n");
- for (a=0;a<num_csts+1;a++)
- next_line (fp, linrec, 0);
- }
- fclose (fp);
- exit (0);
- }
-
- /* Load harmonic constants for desired location */
- while (next_line (fp, linrec, 1)) {
- nojunk (linrec);
- if (curonly)
- if (!strstr (linrec, "Current"))
- continue;
- if (slackcmp (linrec, location))
- continue;
- strcpy (location, linrec);
- /* Is it a current? */
- if (strstr (location, "Current"))
- iscurrent = 1;
- /* Get meridian */
- next_line (fp, linrec, 0);
- meridian = hhmm2seconds (linrec);
- /* Get tzfile, if present */
- if (sscanf (nojunk(linrec), "%s %s", junk, tzfile) < 2)
- strcpy (tzfile, ":UTC");
- /* Get DATUM */
- next_line (fp, linrec, 0);
- assert (sscanf (linrec, "%lf", &DATUM) == 1);
- /* Get constituents */
- for (a=0;a<num_csts;a++) {
- char junk[80];
- next_line (fp, linrec, 0);
- assert (sscanf (linrec, "%s %lf %lf", junk, &(loc_amp[a]),
- &(loc_epoch[a])) == 3);
- assert (loc_amp[a] >= 0.0);
- }
- fclose (fp);
- return;
- }
- if (curonly)
- fprintf (stderr, "Could not find current set '%s' in harmonics file\n",
- location);
- else
- fprintf (stderr, "Could not find location '%s' in harmonics file\n",
- location);
- exit (-1);
- }
-
- /* Check for errors in equilibrium arguments by inferring values from
- neighboring years and comparing with the stored values. This
- function assumes that the values are normalized [0..360). */
- void
- check_epoch ()
- {
- double inferred, stored, error;
- int a, final_year;
- time_t prev_epoch, next_epoch;
- final_year = first_year + num_epochs - 1;
- if (checkyear < first_year || checkyear > final_year) {
- fprintf (stderr, "Tidelib: Don't have equilibrium arguments for %d\n",
- checkyear);
- barf (MISSINGYEAR);
- }
- if (checkyear != first_year) {
- year = checkyear - 1;
- set_epoch ();
- prev_epoch = epoch;
- }
- if (checkyear != final_year) {
- year = checkyear + 1;
- set_epoch ();
- next_epoch = epoch;
- }
- year = checkyear;
- set_epoch ();
- puts ("# Stored Inferred Error");
- for (a=0;a<num_csts;a++) {
- if (checkyear == first_year)
- inferred = fmod (cst_speeds[a] * (-(int)(next_epoch - epoch)) +
- cst_epochs[a][1], 360.0);
- else if (checkyear == final_year)
- inferred = fmod (cst_speeds[a] * (epoch - prev_epoch) +
- cst_epochs[a][final_year-1-first_year], 360.0);
- else {
- double t1, t2;
- t1 = fmod (cst_speeds[a] * (-(int)(next_epoch - epoch)) +
- cst_epochs[a][checkyear+1-first_year], 360.0);
- t2 = fmod (cst_speeds[a] * (epoch - prev_epoch) +
- cst_epochs[a][checkyear-1-first_year], 360.0);
- if (t1 < 0.0)
- t1 += 360.0;
- if (t2 < 0.0)
- t2 += 360.0;
- inferred = (t1 + t2) / 2.0;
- if (fabs (inferred - t1) > 90.0 || fabs (inferred - t2) > 90.0)
- inferred = fmod (inferred + 180.0, 360.0);
- }
- stored = cst_epochs[a][checkyear-first_year];
- if (inferred < 0.0)
- inferred += 360.0;
- error = fabs (stored - inferred);
- if (fabs (stored + 360.0 - inferred) < error)
- error = fabs (stored + 360.0 - inferred);
- if (fabs (stored - inferred - 360.0) < error)
- error = fabs (stored - inferred - 360.0);
- printf ("%d %010.6f %010.6f %f\n", a, stored, inferred, error);
- }
- }
-
- /* Convert YYYY:MM:DD:HH:MM to time_t. Don't know what happens to DST. */
- time_t
- parse_time_string (char *time_string)
- {
- struct tm ht;
- time_t temp;
- if (sscanf (time_string, "%d:%d:%d:%d:%d",
- &(ht.tm_year), &(ht.tm_mon), &(ht.tm_mday), &(ht.tm_hour),
- &(ht.tm_min)) != 5)
- barf (BADTIMESTAMP);
- ht.tm_sec = 0;
- (ht.tm_mon)--;
- ht.tm_year -= 1900;
- ht.tm_isdst = -1;
- if ((temp = mktime (&ht)) == -1)
- barf (BADTIMESTAMP);
- return temp;
- }
-
- /* Return the year for a time_t. This function gets called a lot and might
- be a performance bottleneck if gmtime is slow. */
- int
- yearoftimet (time_t t)
- {
-
- //Since there no gmtime() in THINK C 5.0.4 ANSI library, I'm just going to take
- //localtime() with t as argument, adding gTimezone to it.
- /* return ((gmtime (&t))->tm_year) + 1900;
- */
- static time_t utc_time;
- utc_time =t+gTimezone;
- return (localtime(&utc_time))->tm_year+1900;
-
- }
-
-
- /* Make a reasonable choice for hinc for a given amplitude. */
- void
- pick_hinc ()
- {
- if (amplitude > 30.0)
- hinc = 10;
- else if (amplitude > 15.0)
- hinc = 5;
- else if (amplitude > 8.0)
- hinc = 2;
- else
- hinc = 1;
- }
-
- /* Figure out normalized multipliers for constituents for a particular
- year. Save amplitude for drawing unit lines. */
- static void
- figure_multipliers ()
- {
- int a;
- amplitude = 0.0;
- if (year < first_year || year >= first_year + num_nodes) {
- fprintf (stderr, "Tidelib: Don't have node factors for %d\n", year);
- barf (MISSINGYEAR);
- }
- for (a=0;a<num_csts;a++)
- amplitude += (work[a] = loc_amp[a] * cst_nodes[a][year-first_year]);
- assert (amplitude != 0.0);
- for (a=0;a<num_csts;a++)
- work[a] /= amplitude;
- if (hincmagic)
- pick_hinc ();
- }
-
- /* Doh... Forgot to convert to radians. */
- static double
- cos_degrees (double x)
- {
- //This will speed things up a bit...
- // return cos (x * M_PI / 180.0);
- return cos (x * 0.01745329252);
- }
-
- //This is same routine as cos_degrees(), but compiled to use FPU. I can't
- //test it, since I don't have Mac with FPU.
-
- #pragma options mc68881
- static double
- cos_degrees_fpu (double x)
- {
- return cos (x * 0.01745329252);
- }
- #pragma options !mc68881
-
- /* Re-initialize for a different year */
- void
- happy_new_year (int new_year)
- {
- year = new_year;
- figure_multipliers ();
- set_epoch ();
- }
-
- /* Calculate the normalized tide (-1.0 .. 1.0) for a given time. */
- double
- time2tide (time_t t)
- {
- double tide = 0.0;
- int a, sleepyTime, new_year = yearoftimet (t);
- EventRecord event;
-
- sleepyTime=1;
- WaitNextEvent(everyEvent, &event, sleepyTime, NULL);
- if (new_year != year)
- happy_new_year (new_year);
- if (gHasFPU){
- for (a=0;a<num_csts;a++)
- tide += work[a] *
- cos_degrees_fpu (cst_speeds[a] * ((int)(t - epoch) + meridian) +
- cst_epochs[a][year-first_year] - loc_epoch[a]);
- } else
- {
- for (a=0;a<num_csts;a++)
- tide += work[a] *
- cos_degrees (cst_speeds[a] * ((int)(t - epoch) + meridian) +
- cst_epochs[a][year-first_year] - loc_epoch[a]);
- }
- /* cos((cst_speeds[a] * ((int)(t - epoch) + meridian) +
- cst_epochs[a][year-first_year] - loc_epoch[a])*0.01745329252);*/
- return tide;
- }
-
- /* Calculate the denormalized tide. */
- double
- time2atide (time_t t)
- {
- return time2tide (t) * amplitude + DATUM;
- }
-
- /* Next high tide, low tide, transition of the mark level, or some
- combination.
- Bit Meaning
- 0 low tide
- 1 high tide
- 2 falling transition
- 3 rising transition
- */
- int
- next_big_event (time_t *tm)
- {
- double p, q;
- int flags = 0, slope = 0;
- p = time2atide (*tm);
- *tm += 60;
- q = time2atide (*tm);
- *tm += 60;
- if (p < q)
- slope = 1;
- while (1) {
- if ((slope == 1 && q < p) || (slope == 0 && p < q)) {
- /* Tide event */
- flags |= (1 << slope);
- }
- /* Modes in which to return mark transitions: */
- /* -text (no -graph) */
- /* -graph (no -text) */
- /* -ppm */
- if (mark && ((text && !graphmode) || (!text && graphmode)
- || ppm))
- if ((p > marklev && q <= marklev) || (p < marklev && q >= marklev)) {
- /* Transition event */
- if (p < q)
- flags |= 8;
- else
- flags |= 4;
- if (!(flags & 3)) {
- /* If we're incredibly unlucky, we could miss a tide event if we
- don't check for it here:
-
- . <---- Value that would be returned
- ----------- Mark level
- . .
- */
- p = q;
- q = time2atide (*tm);
- if ((slope == 1 && q < p) || (slope == 0 && p < q)) {
- /* Tide event */
- flags |= (1 << slope);
- }
- }
- }
- if (flags) {
- *tm -= 60;
- /* Don't back up over a transition event, but do back up to where the
- tide changed if possible. If they happen at the same time, then
- we're off by a minute on the tide, but if we back it up it will
- get snagged on the transition event over and over. */
- if (flags < 4)
- *tm -= 60;
- return flags;
- }
- p = q;
- q = time2atide (*tm);
- *tm += 60;
- }
- }
-
- /* Used by do_timestamp. */
- static int
- is_ascii (char a)
- {
- if (a >= ' ' && a <= '~')
- return 1;
- return 0;
- }
-
- /* Generate a timestamp in the appropriate style. */
- void
- do_timestamp (char buf[13], struct tm *t)
- {
- int a;
- if (skinny)
- strftime (buf, 13, "%H%M", t);
- else if (tadjust)
- strftime (buf, 13, "%I:%M %p", t);
- else if (utc)
- strftime (buf, 13, "%H:%M UTC", t);
- else
- strftime (buf, 13, "%I:%M %p %Z", t);
- if (!skinny && buf[0] == '0') {
- if (text && !ppm && !banner)
- buf[0] = ' ';
- else
- #if defined(sun) && !defined(SVR4) && !defined(__svr4__)
- /* Old SunOS */
- {
- for (a=0;a<12;a++)
- buf[a] = buf[a+1];
- }
- #else
- memmove (buf, buf+1, 12);
- #endif
- }
-
- /* Some time zone files don't fill in the time zone properly. We
- can get blanks, or worse yet, unterminated binary garbage. */
- buf[12] = '\0';
- for (a=11;a>=8;a--)
- if (!is_ascii (buf[a]))
- buf[a] = '\0';
- nojunk (buf);
- }
-
- /* Convert a genuine time_t to a specially mangled struct tm. */
- struct tm *
- tmtime (time_t t)
- {
- static time_t utc_time;
- utc_time =t+gTimezone;
- if (tadjust) {
- t += tadjust;
- utc_time =t+gTimezone;
-
- return localtime(&utc_time);
- } else if (utc)
- return localtime(&utc_time);
- else
- return localtime (&t);
- }
-
- /* Find the previous hour-transition from a specified time. */
- time_t
- prev_hour (time_t t)
- {
- struct tm ttm;
- time_t temp;
- static time_t utc_time;
- utc_time =t+gTimezone;
-
- if (utc || tadjust) {
- ttm = *(localtime(&utc_time));
-
- ttm.tm_sec = ttm.tm_min = 0;
- temp = tm2gmt (&ttm) - (tadjust % (long)HOURSECONDS);
- } else {
- ttm = *(localtime (&t));
- ttm.tm_sec = ttm.tm_min = 0;
- temp = mktime (&ttm);
- }
- if (temp <= t - (long)HOURSECONDS)
- temp += (long)HOURSECONDS;
- if (temp > t)
- temp -= (long)HOURSECONDS;
- assert (temp > t - (long)HOURSECONDS && temp <= t);
- return temp;
- }
-
- /* Find the previous day-transition from a specified time. */
- time_t
- prev_day (time_t t)
- {
- struct tm ttm;
- time_t temp;
- static time_t utc_time;
- utc_time =t+gTimezone;
-
- if (utc || tadjust) {
- ttm = *(localtime(&utc_time));
- ttm.tm_sec = ttm.tm_min = ttm.tm_hour = 0;
- temp = tm2gmt (&ttm) - tadjust;
- } else {
- ttm = *(localtime (&t));
- ttm.tm_sec = ttm.tm_min = ttm.tm_hour = 0;
- temp = mktime (&ttm);
- }
- if (temp <= t - (long)DAYSECONDS)
- temp += (long)DAYSECONDS;
- if (temp > t)
- temp -= (long)DAYSECONDS;
- assert (temp > t - (long)DAYSECONDS && temp <= t);
-
- /* If there has been a DST change, the time that we have calculated
- can be wrong. Test for the error, and correct it when found. It
- is assumed that the DST change is by an integer number of hours
- and by no more than 2 hours. */
- if (!(utc || tadjust)) {
- if (localtime(&temp)->tm_hour) {
- int day;
- temp += 3 * (long)HOURSECONDS;
- day = localtime(&temp)->tm_yday;
- while (localtime(&temp)->tm_yday == day)
- temp -= (long)HOURSECONDS;
- temp += (long)HOURSECONDS;
- }
- }
-
- assert (temp > t - (long)HOURSECONDS * 26 && temp <= t);
- return temp;
- }
-
- /* Find the Sunday on which to start a calendar. */
- time_t
- sunday_month (time_t t)
- {
- struct tm ttm;
- int almost_done = 0;
- ttm = *(tmtime(t));
- if (ttm.tm_mday == 1)
- almost_done = 1;
- while (ttm.tm_wday || !almost_done) {
- t = prev_day (t-1);
- ttm = *(tmtime(t));
- if (ttm.tm_mday == 1)
- almost_done = 1;
- }
- return t;
- }
-
- /* Find the next day-transition from a specified time, ASSUMING that the
- parameter passed in is ALREADY on a DAY BOUNDARY. */
- time_t
- increment_day (time_t t)
- {
- time_t iday;
- int day;
- struct tm *ttm;
-
- /* These are easy because there's no DST to worry about */
- if (utc || tadjust)
- return t + (long)DAYSECONDS;
-
- /* Local time is the troublesome case! The following code will work
- provided that the DST change is by an integer number of hours
- and by no more than 2 hours. */
-
- day = localtime(&t)->tm_yday;
- iday = t + (long)HOURSECONDS * 22;
- ttm = localtime(&iday);
- while (ttm->tm_yday == day) {
- iday += (long)HOURSECONDS;
- ttm = localtime(&iday);
- }
-
- /* Insure that we were not caught by a non-integer DST change. */
- assert (!(ttm->tm_min));
-
- return iday;
- }
-
- /* Determine next big event and set up text string for write_high_tide.
- Returns are same as next_big_event. */
- int
- update_high_tide ()
- {
- struct tm *t;
- char *tidedate, *tidetime;
- int event_type;
- prev_ht = next_ht;
- event_type = next_big_event (&next_ht);
- if ((event_type & 2) || graphmode || text || ppm || banner) {
- tidedate = next_ht_date;
- tidetime = next_ht_text;
- } else {
- tidedate = next_lt_date;
- tidetime = next_lt_text;
- }
- if (event_type & 2)
- t = tmtime (next_ht + httimeoff);
- else
- t = tmtime (next_ht + lttimeoff);
- do_timestamp (tidetime, t);
- if (skinny)
- strftime (tidedate, 11, "%m-%d", t);
- else
- strftime (tidedate, 11, "%Y-%m-%d", t);
- return event_type;
- }
-
-
- /**********************************************************************/
-
- /* Calendar and plain text mode */
-
- #define MAXTIDESPERDAY 25
- #define DAYWIDTH 7
- /* static char week[DAYWIDTH*7][MAXTIDESPERDAY*2]; */
- static char **week = NULL;
-
- /* Set one tide in the calendar week being constructed */
- static void
- do_one_calendar_tide (int dayofweek, int tidenumber, int event_type)
- {
- int x;
- char desc, temp[DAYWIDTH];
- double adjust = 0.0;
- assert (tidenumber < MAXTIDESPERDAY - 1); /* Leave room for dates */
- assert (dayofweek < 7);
- if (iscurrent) {
- switch (event_type) {
- case 1:
- desc = 'E';
- break;
- case 2:
- desc = 'F';
- break;
- case 4:
- case 8:
- desc = 'S';
- break;
- default:
- assert (0);
- }
- } else {
- switch (event_type) {
- case 1:
- desc = 'L';
- adjust = ltleveloff;
- break;
- case 2:
- desc = 'H';
- adjust = htleveloff;
- break;
- case 4:
- desc = 'F';
- break;
- case 8:
- desc = 'R';
- break;
- default:
- assert (0);
- }
- }
- week[dayofweek*DAYWIDTH][2+tidenumber*2] = desc;
- for (x=0;x<(int)(strlen(next_ht_text));x++)
- week[dayofweek*DAYWIDTH+x+1][2+tidenumber*2] = next_ht_text[x];
- /* This will die horribly if the amplitude is too big. */
- sprintf (temp, "%0.2f", adjust + time2atide (next_ht));
- for (x=0;x<(int)(strlen(temp));x++)
- week[dayofweek*DAYWIDTH+x][3+tidenumber*2] = temp[x];
- }
-
- /* Do one day for a calendar. */
- static void
- do_calendar_day (time_t start, time_t stop, int dayofweek, int *maxline)
- {
- int tidenumber = 0, event_type, x;
- next_ht = start - 180; /* Don't miss tides that happen at midnight */
- while (1) {
- event_type = update_high_tide ();
- if (next_ht < start)
- continue;
- if (next_ht >= stop)
- break;
-
- /* Add date stamp from first tide (hope we get one) */
- if (tidenumber == 0)
- for (x=0;x<(int)(strlen(next_ht_date));x++)
- week[dayofweek*DAYWIDTH+x][0] = next_ht_date[x];
-
- /* Refer to list_tides to understand why this is like this. */
- if ((event_type & 4) && (event_type & 1))
- do_one_calendar_tide (dayofweek, tidenumber++, 4);
- if ((event_type & 8) && (event_type & 2))
- do_one_calendar_tide (dayofweek, tidenumber++, 8);
- if (event_type & 1)
- do_one_calendar_tide (dayofweek, tidenumber++, 1);
- if (event_type & 2)
- do_one_calendar_tide (dayofweek, tidenumber++, 2);
- if ((event_type & 4) && !(event_type & 1))
- do_one_calendar_tide (dayofweek, tidenumber++, 4);
- if ((event_type & 8) && !(event_type & 2))
- do_one_calendar_tide (dayofweek, tidenumber++, 8);
-
- if (3+(tidenumber-1)*2 > *maxline)
- *maxline = 3+(tidenumber-1)*2;
- }
- }
-
- /* Do one week for a calendar. */
- static time_t
- do_calendar_week (time_t start)
- {
- int x, y, maxline = 0, dayofweek;
- time_t stop;
- for (x=0;x<DAYWIDTH*7;x++)
- for (y=0;y<MAXTIDESPERDAY*2;y++)
- week[x][y] = ' ';
- start = prev_day (start);
- stop = increment_day (start);
- for (dayofweek=0;dayofweek<7;dayofweek++) {
- do_calendar_day (start, stop, dayofweek, &maxline);
- start = stop;
- stop = increment_day (stop);
- }
- for (y=0;y<=maxline;y++) {
- for (x=0;x<DAYWIDTH*7;x++)
- putchar (week[x][y]);
- printf ("\n");
- }
- return start;
- }
-
- /* Do a calendar. */
- void
- do_calendar ()
- {
- time_t start = sunday_month (faketime);
- int month = tmtime(faketime)->tm_mon, looper;
-
- if (!week) {
- /* Allocate storage */
- assert (week = (char **) malloc (DAYWIDTH*7 * sizeof (char *)));
- for (looper=0;looper<DAYWIDTH*7;looper++) {
- assert (week[looper] = (char *) malloc (MAXTIDESPERDAY*2*sizeof(char)));
- }
- }
-
- puts (location);
- if (mark && !iscurrent)
- printf ("Mark level: %f\n", marklev);
- printf ("\nSunday Monday Tuesda Wednes Thursd Friday Saturday\n");
- do {
- printf ("\n");
- start = do_calendar_week (start);
- } while (tmtime(start)->tm_mon != (month+1)%12);
- }
-
- /* List several days of high and low tides to standard output. This
- got ugly because of the need to make things come out in the right order
- with the enhanced mark code. */
- void
- list_tides (void)
- {
- int a, event_type;
- char *high, *low, *rise, *fall;
- next_ht = faketime;
- if (iscurrent) {
- high = " Max Flood";
- low = " Max Ebb";
- rise = fall = "Slack Water";
- } else {
- high = " High Tide";
- low = " Low Tide";
- rise = " Rising";
- fall = " Falling";
- }
- puts (location);
- if (mark && !iscurrent)
- printf ("Mark level: %f\n", marklev);
- if (httimeoff || lttimeoff || htleveloff != 0.0 || ltleveloff != 0.0)
- printf ("Offsets: hloff=%f htoff=%dmin lloff=%f ltoff=%dmin\n",
- htleveloff, httimeoff/60, ltleveloff, lttimeoff/60);
- if (text < 1)
- text = 21;
- for (a=0;a<text;a++) {
- event_type = update_high_tide ();
- if ((event_type & 4) && (event_type & 1)) {
- printf ("%s: %s %s %0.2f\n", fall, next_ht_date, next_ht_text,
- time2atide (next_ht));
- }
- if ((event_type & 8) && (event_type & 2)) {
- printf ("%s: %s %s %0.2f\n", rise, next_ht_date, next_ht_text,
- time2atide (next_ht));
- }
- if (event_type & 1) {
- printf ("%s: %s %s %0.2f\n", low, next_ht_date, next_ht_text,
- ltleveloff + time2atide (next_ht));
- }
- if (event_type & 2) {
- printf ("%s: %s %s %0.2f\n", high, next_ht_date, next_ht_text,
- htleveloff + time2atide (next_ht));
- }
- if ((event_type & 4) && !(event_type & 1)) {
- printf ("%s: %s %s %0.2f\n", fall, next_ht_date, next_ht_text,
- time2atide (next_ht));
- }
- if ((event_type & 8) && !(event_type & 2)) {
- printf ("%s: %s %s %0.2f\n", rise, next_ht_date, next_ht_text,
- time2atide (next_ht));
- }
- }
- }
-
-
- /**********************************************************************/
-
-
- /* Banner mode */
- #define BANNERWIDTH 68
- #define BANNERSTART 11
- void
- do_banner ()
- {
- int a, b, c, markchar, middlechar, mllwchar;
- struct tm *t;
- time_t curtime;
- char bdate[6], btime[5], buf[80], tbuf[80];
- if (text < 1)
- text = 21;
- curtime = next_ht = faketime;
- puts (location);
- /* Initialize the amplitude. */
- happy_new_year (yearoftimet (faketime));
- if (mark) {
- if (!iscurrent)
- printf ("Mark level: %f\n", marklev);
- markchar = (int)((double)BANNERWIDTH * (((marklev - DATUM) / amplitude)
- * 0.5 + 0.5)) + BANNERSTART;
- if (markchar < BANNERSTART || markchar > 78)
- mark = 0;
- }
- if (middle)
- middlechar = BANNERWIDTH / 2 + BANNERSTART;
- if (mllw) {
- mllwchar = (int)((double)BANNERWIDTH * (((-DATUM) / amplitude)
- * 0.5 + 0.5)) + BANNERSTART;
- if (mllwchar < BANNERSTART || mllwchar > 78)
- mllw = 0;
- }
- buf[79] = '\0';
- update_high_tide ();
- for (a=0;a<text;a++) {
- t = tmtime (curtime);
- strftime (btime, 5, "%H%M", t);
- strftime (bdate, 6, "%m-%d", t);
- b = (int)((double)BANNERWIDTH * (time2tide(curtime) * 0.5 + 0.5))
- + BANNERSTART;
- sprintf (buf, "%s %s ", bdate, btime);
- if (iscurrent) {
- for (c=BANNERSTART;c<79;c++)
- buf[c] = ' ';
- if (b < markchar)
- for (c=b;c<markchar;c++)
- buf[c] = '*';
- else
- for (c=markchar+1;c<=b;c++)
- buf[c] = '*';
- } else {
- for (c=BANNERSTART;c<=b;c++)
- buf[c] = '*';
- for (c=b+1;c<79;c++)
- buf[c] = ' ';
- }
- if (mark)
- buf[markchar] = '|';
- if (middle)
- buf[middlechar] = '|';
- if (mllw)
- buf[mllwchar] = '|';
- if (curtime+(tstep>>1) >= next_ht) {
- sprintf (tbuf, "%s %0.2f", next_ht_text, time2atide (next_ht));
- strncpy (buf+BANNERSTART+1, tbuf, strlen (tbuf));
- while (curtime+(tstep>>1) >= next_ht)
- update_high_tide ();
- }
- puts (buf);
- curtime += tstep;
- }
- }
-
-
- /**********************************************************************/
-
-
- /* ASCII graph mode was done by Jef Poskanzer. */
- /* Generate an ASCII graph of the tides. */
- #define TEXTHEIGHT 14
- #define TTEXTHEIGHT 10
- static char textmap[TEXTWIDTH*TEXTHEIGHT];
- static void t_setchr (int x, int y, char chr) {
- if (x < 0 || y < 0 || x >= TEXTWIDTH || y >= TEXTHEIGHT)
- return;
- textmap[y*TEXTWIDTH+x] = chr;
- }
- static char t_getchr (int x, int y) {
- if (x < 0 || y < 0 || x >= TEXTWIDTH || y >= TEXTHEIGHT)
- return '\0';
- return textmap[y*TEXTWIDTH+x];
- }
- static double t_tide2wl (double tide) {
- return ((double)TTEXTHEIGHT) * (-tide) * 0.5 + (double)TTEXTHEIGHT * 0.5;
- }
- static double t_wl2tide (int y) {
- return -2.0*(y - TTEXTHEIGHT * 0.5) / ((double)TTEXTHEIGHT);
- }
- static void t_putstr (int x, int y, char *s) {
- int a;
- for (a=0;a<(int)(strlen(s));a++)
- t_setchr (x+a, y, s[a]);
- }
- static void t_center_text (int x, int y, char *text)
- {
- int l = strlen (text);
- t_putstr (x - l / 2, y, text);
- }
- static void t_write_tide (int slope, int x)
- {
- if (slope) {
- t_center_text (x, TTEXTHEIGHT, next_ht_date);
- t_center_text (x, TTEXTHEIGHT+1, next_ht_text);
- } else {
- t_center_text (x, TTEXTHEIGHT+2, next_ht_date);
- t_center_text (x, TTEXTHEIGHT+3, next_ht_text);
- }
- }
- void
- tide2ascii (void)
- {
- int x, y, event_type, midwl;
- time_t start = faketime, this_time = time(NULL);
-
- puts (location);
- if (mark && !iscurrent)
- printf ("Mark level: %f\n", marklev);
-
- /* Set the background. */
- for (x=0;x<TEXTWIDTH;x++)
- for (y=0;y<TEXTHEIGHT;y++)
- t_setchr (x, y, ' ');
-
- /* Initialize the amplitude. */
- happy_new_year (yearoftimet (faketime));
-
- /* Draw day separators. */
- if (lines) {
- time_t day;
- for (day=prev_day(start);day<start+TEXTWIDTH*tstep;
- day=increment_day(day)) {
- x = (int)((day - start) / tstep + 0.5);
- for (y=0;y<TEXTHEIGHT;y++)
- t_setchr (x, y, '|');
- }
- }
-
- /* Draw the tides. */
- midwl = (int)(t_tide2wl (-DATUM / amplitude) + 0.5);
- for (x=0;x<TEXTWIDTH;x++) {
- int yy = (int)(t_tide2wl (time2tide (faketime)) + 0.5);
- if (iscurrent) {
- if (yy < midwl)
- for (y=midwl-1;y>=yy;y--)
- t_setchr (x, y, '*');
- else
- for (y=midwl+1;y<=yy;y++)
- t_setchr (x, y, '*');
- } else {
- for (y=TTEXTHEIGHT-1;y>=yy;y--)
- t_setchr (x, y, '*');
- }
- faketime += tstep;
- }
-
- /* Extra lines */
- if (mark) {
- y = (int) (t_tide2wl ((marklev - DATUM) / amplitude) + 0.5);
- for (x=0;x<TEXTWIDTH;x++)
- if (t_getchr (x, y) == '*' || iscurrent)
- t_setchr (x, y, '-');
- }
- if (middle) {
- y = (int) (t_tide2wl (0.0) + 0.5);
- for (x=0;x<TEXTWIDTH;x++)
- if (t_getchr (x, y) == '*')
- t_setchr (x, y, '-');
- }
- if (mllw) {
- y = (int) (t_tide2wl (-DATUM / amplitude) + 0.5);
- for (x=0;x<TEXTWIDTH;x++)
- if (t_getchr (x, y) == '*')
- t_setchr (x, y, '-');
- }
-
- if (now) {
- /* X marks the spot */
- x = (int)((this_time - start) / tstep);
- y = (int) (t_tide2wl (time2tide (this_time)) + 0.5);
- t_setchr (x, y, '+');
- }
-
- /* Scrawl timestamps */
- next_ht = start;
- event_type = update_high_tide ();
- while (next_ht < start + TEXTWIDTH*tstep) {
- t_write_tide ((event_type & 2), (int)((next_ht - start) / tstep + 0.5));
- event_type = update_high_tide ();
- }
-
- /* Write output. */
- for (y=TTEXTHEIGHT;y<TTEXTHEIGHT+2;y++) {
- printf("[");
- for (x=0;x<TEXTWIDTH;x++)
- putchar(t_getchr(x,y));
- printf("]\n");
- }
- for (y=0;y<TTEXTHEIGHT;y++) {
- double temp;
- printf("[");
- for (x=0;x<TEXTWIDTH;x++)
- putchar(t_getchr(x,y));
- temp = t_wl2tide(y) * amplitude + DATUM;
- /* Chop off minus sign for super-low tides to save space */
- if (temp <= -10.0)
- temp = -temp;
- printf("]%0.1f\n", temp);
- }
- for (y=TTEXTHEIGHT+2;y<TTEXTHEIGHT+4;y++) {
- printf("[");
- for (x=0;x<TEXTWIDTH;x++)
- putchar(t_getchr(x,y));
- printf("]\n");
- }
- }
-
-
-
- /**********************************************************************/
-
-
- /* Generate a PPM graph of the tides. While we're at it, re-invent the
- wheel.
- */
- static int BGR = 135;
- static int BGG = 206;
- static int BGB = 235;
- static int FGR = 0;
- static int FGG = 0;
- static int FGB = 255;
- static int EBR = 46;
- static int EBG = 139;
- static int EBB = 87;
- static int TXR = 0;
- static int TXG = 0;
- static int TXB = 0;
- static int MKR = 255;
- static int MKG = 0;
- static int MKB = 0;
- static int MDR = 255;
- static int MDG = 255;
- static int MDB = 0;
- static int MLR = 255;
- static int MLG = 255;
- static int MLB = 255;
- #define margin 0.05
- unsigned char *pixmap;
- /* Colors must be specified in the form rgb:hh/hh/hh, where hh is a 2-byte
- hexidecimal number. */
- static void p_parsecolor (int *r, int *g, int *b, char *col) {
- if (col) {
- if (sscanf (col, "rgb:%x/%x/%x", r, g, b) != 3)
- barf (BADCOLORSPEC);
- }
- if (!((*r >= 0 && *r <= 255)&&(*g >= 0 && *g <= 255)&&
- (*b >= 0 && *b <= 255)))
- barf (BADCOLORSPEC);
- }
- static void p_parseallcolors ()
- {
- p_parsecolor (&FGR, &FGG, &FGB, fgrise_color_arg);
- p_parsecolor (&EBR, &EBG, &EBB, fgfall_color_arg);
- p_parsecolor (&TXR, &TXG, &TXB, fgtext_color_arg);
- p_parsecolor (&MKR, &MKG, &MKB, fgmark_color_arg);
- p_parsecolor (&MLR, &MLG, &MLB, fgmllw_color_arg);
- p_parsecolor (&MDR, &MDG, &MDB, fgmiddle_color_arg);
- p_parsecolor (&BGR, &BGG, &BGB, bg_color_arg);
- }
- static void p_setval (int x, int y, int c, int val) {
- if (x < 0 || y < -12 || x >= PPMWIDTH || y >= PPMHEIGHT)
- return;
- pixmap[((y+12)*PPMWIDTH+x)*3+c] = (unsigned char)val;
- }
- static int p_getval (int x, int y, int c) {
- if (x < 0 || y < -12 || x >= PPMWIDTH || y >= PPMHEIGHT)
- return 0;
- return (int) (pixmap[((y+12)*PPMWIDTH+x)*3+c]);
- }
- static void p_setpix (int x, int y, int r, int g, int b) {
- p_setval (x, y, 0, r);
- p_setval (x, y, 1, g);
- p_setval (x, y, 2, b);
- }
- static int p_interp (int a, int b, double x) {
- return (int)((double)a + x * (double)(b-a) + 0.5);
- }
- static double p_tide2wl (double tide) {
- return ((double)PPMHEIGHT * (1.0 - 2.0 * margin)) * (-tide) * 0.5
- + (double)PPMHEIGHT * 0.5;
- }
- static double p_wl2tide (int y) {
- return -2.0*(y - PPMHEIGHT * 0.5) / ((double)PPMHEIGHT *
- (1.0 - 2.0 * margin));
- }
- static void p_putglyph (int x, int y, char glyph) {
- int base = (int)(glyph - ' '), xl, yl;
- assert (base >= 0 && base < 95);
- base *= 7;
- for (yl=0;yl<11;yl++)
- for (xl=0;xl<7;xl++)
- if (glyphs[yl][base+xl])
- p_setpix (x+xl, y+yl, TXR, TXG, TXB);
- }
- static void p_putstr (int x, int y, char *s) {
- int a;
- for (a=0;a<(int)(strlen(s));a++)
- p_putglyph (x+a*7, y, s[a]);
- }
- static void p_center_text (int x, int y, char *text)
- {
- int l = strlen (text);
- p_putstr (x - 7 * l / 2, y, text);
- }
- static void p_write_high_tide (int x)
- {
- p_center_text (x, 1, next_ht_date);
- p_center_text (x, 13, next_ht_text);
- }
- static void p_write_trans_time (int x)
- {
- int bottom = PPMHEIGHT - 19;
- if (tinc)
- bottom -= 12;
- p_center_text (x, bottom-12, next_ht_date);
- p_center_text (x, bottom, next_ht_text);
- }
- static void p_draw_depth_lines (int *tmax, int *tmin)
- {
- int a, x, y;
- if (lines) {
- *tmin = 30;
- *tmax = PPMHEIGHT - 14;
- if (mark)
- *tmax -= 24;
- if (tinc)
- *tmax -= 12;
- *tmin = (int) (p_wl2tide (*tmin) * amplitude + DATUM);
- *tmax = (int) (ceil (p_wl2tide (*tmax) * amplitude + DATUM));
- for (a=*tmax;a<=*tmin;a++) {
- if (amplitude > 30.0 && (a % 10))
- continue;
- y = (int) p_tide2wl (((double)a - DATUM) / amplitude);
- if (hinc) {
- if (!(a % hinc)) {
- char temp[5];
- int l;
- sprintf (temp, "%d", abs(a));
- l = strlen (temp);
- for (x=0;x<PPMWIDTH-7*l-2;x++)
- p_setpix (x, y, TXR, TXG, TXB);
- continue;
- }
- }
- for (x=0;x<PPMWIDTH;x++)
- p_setpix (x, y, TXR, TXG, TXB);
- }
- }
- }
- void
- tide2ppm (char *outfile)
- {
- FILE *fp;
- int x, y, event_type, a, tmax, tmin, midwl;
- time_t start = faketime, this_time = time(NULL);
-
- assert (sizeof (unsigned char) == 1);
- assert (pixmap = (unsigned char *) malloc (3 * PPMWIDTH *
- (PPMHEIGHT + 12)));
-
- p_parseallcolors ();
-
- /* Set the background. */
- for (x=0;x<PPMWIDTH;x++)
- for (y=-12;y<PPMHEIGHT;y++)
- p_setpix (x, y, BGR, BGG, BGB);
-
- /* Initialize the amplitude before drawing the depth lines. */
- happy_new_year (yearoftimet (faketime));
-
- if (!toplines)
- p_draw_depth_lines (&tmax, &tmin);
-
- /* Draw the tides. */
- midwl = (int)(p_tide2wl (-DATUM / amplitude));
- for (x=0;x<PPMWIDTH;x++) {
- double i, yy = p_tide2wl (time2tide (faketime));
- if (iscurrent) {
- if ((int)yy < midwl) {
- for (y=midwl-1;y>(int)yy;y--)
- p_setpix (x, y, FGR, FGG, FGB);
- /* Anti-aliasing */
- i = yy - floor (yy);
- p_setval (x, (int)yy, 0, p_interp (FGR, p_getval (x, (int)yy, 0), i));
- p_setval (x, (int)yy, 1, p_interp (FGG, p_getval (x, (int)yy, 1), i));
- p_setval (x, (int)yy, 2, p_interp (FGB, p_getval (x, (int)yy, 2), i));
- } else {
- for (y=midwl+1;y<=(int)yy;y++)
- p_setpix (x, y, EBR, EBG, EBB);
- /* Anti-aliasing */
- i = yy - floor (yy);
- p_setval (x, (int)yy+1, 0, p_interp (p_getval (x, (int)yy+1, 0), EBR,
- i));
- p_setval (x, (int)yy+1, 1, p_interp (p_getval (x, (int)yy+1, 1), EBG,
- i));
- p_setval (x, (int)yy+1, 2, p_interp (p_getval (x, (int)yy+1, 2), EBB,
- i));
- }
- } else {
- for (y=PPMHEIGHT-1;y>(int)yy;y--)
- p_setpix (x, y, FGR, FGG, FGB);
- /* Anti-aliasing */
- i = yy - floor (yy);
- p_setval (x, (int)yy, 0, p_interp (FGR, p_getval (x, (int)yy, 0), i));
- p_setval (x, (int)yy, 1, p_interp (FGG, p_getval (x, (int)yy, 1), i));
- p_setval (x, (int)yy, 2, p_interp (FGB, p_getval (x, (int)yy, 2), i));
- }
- faketime += tstep;
- }
-
- if (toplines)
- p_draw_depth_lines (&tmax, &tmin);
-
- /* Label unit lines */
- if (hinc) {
- for (a=tmax;a<=tmin;a++) {
- if (!(a % hinc)) {
- char temp[5];
- int l;
- y = (int) p_tide2wl (((double)a - DATUM) / amplitude);
- sprintf (temp, "%d", abs(a));
- l = strlen (temp);
- p_putstr (PPMWIDTH - 7 * l, y-4, temp);
- }
- }
- }
-
- /* Extra lines */
- if (mark) {
- y = (int) p_tide2wl ((marklev - DATUM) / amplitude);
- for (x=0;x<PPMWIDTH;x++)
- p_setpix (x, y, MKR, MKG, MKB);
- }
- if (middle) {
- y = (int) p_tide2wl (0.0);
- for (x=0;x<PPMWIDTH;x++)
- p_setpix (x, y, MDR, MDG, MDB);
- }
- if (mllw) {
- y = (int) p_tide2wl (-DATUM / amplitude);
- for (x=0;x<PPMWIDTH;x++)
- p_setpix (x, y, MLR, MLG, MLB);
- }
-
- /* Draw tick marks */
- if (lines) {
- time_t hour, prevday;
- prevday = prev_day (start);
- for (hour=prev_hour(start);hour<=start+PPMWIDTH*tstep+(long)HOURSECONDS;
- hour+=(long)HOURSECONDS) {
- x = (hour - start) / tstep;
- for (y=PPMHEIGHT-1;y>PPMHEIGHT-8;y--)
- p_setpix (x, y, TXR, TXG, TXB);
- if (tinc) {
- if (!(((hour - prevday) / 3600) % tinc)) {
- char buf[13];
- do_timestamp (buf, tmtime (hour));
- if (buf[1] == ':')
- buf[1] = '\0';
- else
- buf[2] = '\0';
- p_center_text (x, PPMHEIGHT-19, buf);
- }
- }
- }
- for (hour=prevday;hour<=start+PPMWIDTH*tstep+(long)HOURSECONDS;
- hour=increment_day(hour)) {
- x = (hour - start) / tstep;
- for (y=PPMHEIGHT-1;y>PPMHEIGHT-8;y--) {
- p_setpix (x-1, y, TXR, TXG, TXB);
- p_setpix (x+1, y, TXR, TXG, TXB);
- }
- }
- }
-
- if (now) {
- int looper;
- /* X marks the spot */
- x = (int)((this_time - start) / tstep);
- y = (int) p_tide2wl (time2tide (this_time));
- for (looper=-4;looper<=4;looper++) {
- p_setpix (x+looper, y, TXR, TXG, TXB);
- p_setpix (x, y+looper, TXR, TXG, TXB);
- }
- }
-
- /* Scrawl timestamps */
- next_ht = start;
- event_type = update_high_tide ();
- while (next_ht < start + PPMWIDTH*tstep) {
- x = (int)((next_ht - start) / tstep);
- if (event_type & 3)
- p_write_high_tide (x);
- if (event_type & 12) {
- p_write_trans_time (x);
- for (y=PPMHEIGHT-1;y>=PPMHEIGHT-7;y--)
- p_setpix (x, y, MKR, MKG, MKB);
- }
- event_type = update_high_tide ();
- }
-
- /* Identify the pixmap */
- p_center_text (PPMWIDTH>>1, -11, location);
-
- /* Write output. */
- if (strcmp (outfile, "-")) {
- #ifdef OS2
- if (!(fp = fopen (outfile, "wb")))
- #else
- if (!(fp = fopen (outfile, "w")))
- #endif
- barf (CANTOPENFILE);
- }
- else
- fp = stdout;
- fprintf (fp, "P6\n%d %d\n255\n", PPMWIDTH, PPMHEIGHT+12);
- fwrite (pixmap, 3, PPMWIDTH*(PPMHEIGHT+12), fp);
- fclose (fp);
- free (pixmap);
- }
-
- //Following routines are exclusively for Mac
-
- short NumToolboxTraps( void )
- {
- if (NGetTrapAddress(_InitGraf, ToolTrap) ==
- NGetTrapAddress(0xAA6E, ToolTrap))
- return(0x0200);
- else
- return(0x0400);
- }
-
- TrapType GetTrapType(short theTrap)
- {
-
- if ((theTrap & TrapMask) > 0)
- return(ToolTrap);
- else
- return(OSTrap);
-
- }
-
-
- Boolean TrapAvailable(short theTrap)
- {
-
- TrapType tType;
-
- tType = GetTrapType(theTrap);
- if (tType == ToolTrap)
- theTrap = theTrap & 0x07FF;
- if (theTrap >= NumToolboxTraps())
- theTrap = _Unimplemented;
-
- return (NGetTrapAddress(theTrap, tType) !=
- NGetTrapAddress(_Unimplemented, ToolTrap));
- }
-
-
- Boolean WNEAvailable(void)
- {
- return TrapAvailable(_WaitNextEvent);
- }
-
-
- void FindIfHasFPU(Boolean answer)
- {
- long response;
-
- if (TrapAvailable(_Gestalt)){
-
- assert(!Gestalt(gestaltFPUType, &response));
- if (response == gestaltNoFPU) answer=FALSE;
- else answer=TRUE;
- } else {
- answer=FALSE;
- }
- }
-
- void FindTimeZone(void)
- {
- MachineLocation loc;
-
- ReadLocation(&loc);
- gTimezone = (short)(loc.gmtFlags.gmtDelta & 0x00FFFFFF);
- }